Start Clean 1.2
Written
by Sphinx
þ Topic : Register Crack. Nag Crack. Keygenning.
þ Date : 05/30/2000
þ Level : Beginner
þ Protection : Serial
þ Additional : Nag
|
SoftICE
W32Dasm
Hiew
Turbo C
|
http://www.idca.com/~thesandman/sandman.html (The Sandman)
|
--[ Register Crack ]----------------------------------------------------------
After running Start Clean, we get a nag. Click on Register. Enter
a name
and a bogus serial. We get the message "Incorrect code!". So
we're wrong...
- Disassemble [startcln.bak] (backup)
Usually, searching for the error message in SDR (String Data Refs)
then
searching above it a conditional jump, then inverting it (eg.
from "je" to
"jne") does it. It also works here, BUT, notice when you've pressed
OK,
you won't see your name after "Registered to" and when you restart,
you're
prompted again, with the nag!
So we'll use another method instead. We'll search for some infos/strings
from the Register dialog.
- Search for "Enter" (from Enter Registration Info) in the dead listing
You see:
Name: DialogID_0078, # of Controls=006, Caption:"Enter
Registration Info"
...
005 - ControlID:FFFF,
Control Class:"STATIC" Control Text:"Name:"
006 - ControlID:FFFF,
Control Class:"STATIC" Control Text:"Code:"
Yep, that's what you see when you click on [Register].
So from here we'll search for "DialogID_0078" (the second one)
You see:
* Possible Reference to Dialog: DialogID_0078, CONTROL_ID:0406,
""
...
* Reference To: KERNEL32.lstrcmpA, Ord:0269h <-------------------
the API
|
:004011E3 FF1520924000 Call dword
ptr [00409220]
:004011E9 85C0
test eax, eax
:004011EB 0F8580000000 jne 00401271
<-----------------HERE!
:004011F1 8D44240C
lea eax, dword ptr [esp+0C]
:004011F5 8D4C2408
lea ecx, dword ptr [esp+08]
:004011F9 50
push eax
:004011FA 51
push ecx
:004011FB 8D942418010000 lea edx, dword ptr [esp+00000118]
:00401202 6A00
push 00000000
:00401204 683F000F00
push 000F003F
:00401209 6A00
push 00000000
The API lstrcmpA - Just by merely looking at it, you'll
realize that it's
for StringCompare. So you're curious about the conditional
jump after the
call to the API. Highlight it and take note the offset
seen under W32Dasm,
mine was @Offset 000005EBh. Here's the file offset where
we'll patch the
"jne" (75h) with "je" (74h) to invert the jump.
- Exit W32Dasm. Hiew [startcln.exe] (31.744 bytes)
- Press [F4] and choose Decode
Press [F5] and type 5EB
Press [F3] and patch "jne" with "je"
Press [F9] to update
Press [F10] to quit
- Run Start Clean. Register. Type your name and the (optional)
serial :)
then hit [enter]
Wow! We're right! Start Clean is registered to your name. Another cracked!
BTW: Patching the EXE makes it an instant keygen! After registering
it, run
REGEDIT and goto HKCU\Software\Start
Clean\Configuration. You'll see
your real code so that you can *legally*
register it (ie. no patching)
--[ Nag Crack ]---------------------------------------------------------------
Suppose you only want to remove the nag and you haven't done the
register
crack yet (otherwise, it'll be pointless), removing it is so
EASY, we don't
need to use a debugger.
- Reload [startcln.bak] in W32Dasm. Like above, we'll search for
some infos
from the nag screen. Search for "Register"
You see:
Name: DialogID_006F, # of Controls=010, Caption:"Register!",
ClassName:""
...
009 - ControlID:0002,
Control Class:"BUTTON" Control Text:"OK"
010 - ControlID:040C,
Control Class:"BUTTON" Control Text:"&Register"
Yep, that's what you see on the nag screen.
So from here we'll search for "DialogID_006F"
You see:
* Reference To: COMCTL32.InitCommonControls, Ord:0011h
|
:00401EA9 FF1508924000
Call dword ptr [00409208]
:00401EAF E84CF1FFFF
call 00401000
:00401EB4 A34C724000
mov dword ptr [0040724C], eax
:00401EB9 85C0
test eax, eax
:00401EBB 7524
jne 00401EE1 <-------------HERE!
:00401EBD 6A00
push 00000000
:00401EBF A148724000
mov eax, dword ptr [00407248]
:00401EC4 68F0274000
push 004027F0
:00401EC9 6A00
push 00000000
* Possible Reference to Dialog: DialogID_006F <----------------
nag dialog
|
:00401ECB 6A6F
push 0000006F
:00401ECD 50
push eax
...
Here we can use the usual way of cracking in W32Dasm. Above
the DialogID
which calls the nag, there's a conditional jump. Tracing
through the jump
(ie. highlight it then press [right]). You'll realize
that it's the main
program!
if regged, jump to 401EE1 (main)
if unregged, continue, reaching DialogID_0064 (nag)
So to crack this, we'll patch the condtional jump (but
NOT inverting it,
doing that shows the nag if we're registered, very nasty!)
to make us
always the jump to the main program whether we're regged
or not. So we'll
patch the "jne" (75h) to "jmps" (EBh). First, highlight
it then note the
offset seen, mine was @Offset 000012BBh.
- Exit W32Dasm. Hiew [startcln.exe] (31.744 bytes)
- Press [F4] and choose Decode
Press [F5] and type 12BB
Press [F3] and patch "jne" with "jmps" (jump short)
Press [F9] to update
Press [F10] to quit
- Run Start Clean (make sure we're unregged else delete the registry key).
Wow! No more nag! But still shareware :(
--[ Keygenning (my first!) ]--------------------------------------------------
Making a keygen requires intermediate knowledge of assembly, but
in this
case, not really. The protection used here is weak, so I guess
a basic
knowledge of assembly (and a know-how in SoftICE) will suffice.
Now run Start Clean and goto registration portion. I entered:
Name: Sphinx <---
varying lengths will help in determining which
Code: 12345
string is being processed
First of all, we need to break into the program (no symbol loader
needed)
and since we'll enter text in a dialog box, we assume it uses:
GetDlgItemTextA <---
with A since it's a 32-bit program
GetWindowTextA
But if we search the EXE, we'll only find GetDlgItemTextA. So
in SoftICE,
set the necessary breakpoint, by typing:
- bpx GetDlgItemTextA [enter]
- Press F5 (or Ctrl-D) to exit SoftICE. We're now back to the app.
- Press Ok...and...SoftICE breaks at GetDlgItemTextA! We're right!
But hmmm...we're not yet in the Start Clean code. So,
press F12 (twice).
1st F12, eax = namelength
2nd F12, eax = codelength
You see: (as disassembled in W32Dasm - notice no hexcodes)
:004011C7 push 00406030
:004011CC push 00406130
:004011D1 call 00401280
<- calculation routine
:004011D6 lea eax, dword ptr [esp+18]
:004011DA add esp, 00000008
:004011DD push eax
:004011DE push 00406030
If you pressed F10 (Procedure Step) to skip entering the
calc routine,
you'll notice eax whill change. Now type "d eax" and you'll
see your real
code, so we know that "call 00401280" is the one.
- So while the call is highlighted, press F8 (Trace) to step into the call.
You see:
* Referenced by a CALL at Addresses:
|:0040111F , :004011D1
...
...
* Reference To: USER32.wsprintfA, Ord:0249h
:004012B5 Call dword ptr [004092D4]
:004012BB mov ebx, dword ptr [esp+0000011C] <-
ebx = offset of name
:004012C2 add esp, 00000008
:004012C5 mov eax, ebx
<- eax = offset of name
eax and ebx have the same
value (offset of name)
type "d eax" to check
* Reference To: USER32.CharNextA, Ord:001Eh
:004012C7 mov edi, dword ptr [004092DC]
:004012CD cmp byte ptr [ebx], 00
<- cmp if byte at [ebx] is 00 (null)
:004012D0 je 004012E1
<- if equal, jump, else...
* Referenced by a (U)nconditional or (C)onditional
Jump at Address:
|:004012DF(C)
|
:004012D2 movsx ecx, byte ptr [eax]
<- move byte from [eax] to ecx
so ecx = 53 ('S')
:004012D5 push eax
<- save eax
:004012D6 lea ebp, dword ptr [ebp+2*ecx] <-
ebp = ecx * 2 + ebp
= 53 * 2 + 6A
6A is a constant 1st value.
ebp = 110
:004012DA call edi
<- prepare next char
:004012DC cmp byte ptr [eax], 00
<- is byte at [eax] = 00?
:004012DF jne 004012D2
<- no? then loop for next char
calculation until eax=00
(ie. no char left))
If done, ebp=55E (1374 in dec)
Remember that.
* Referenced by a (U)nconditional or (C)onditional
Jump at Address:
|:004012D0(C)
|
:004012E1 lea eax, dword ptr [esp+10]
<- eax = offset where the codes
are to be placed. So,
at first, "d eax" will
show nothing.
:004012E5 push ebp
<- save ebp (1374)
* Possible StringData Ref from Data Obj ->"%d-" <- 1st format: code1-
:004012E6 push 00406274
:004012EB push eax
* Reference To: USER32.wsprintfA, Ord:0249h
:004012EC Call dword ptr [004092D4]
:004012F2 lea eax, dword ptr [esp+1C]
:004012F6 add esp, 0000000C
:004012F9 push eax
:004012FA push esi
* Reference To: KERNEL32.lstrcatA, Ord:0266h <-
after this, "d eax", you
will see the ebp value
with '-' (ie. 1374- )
:004012FB Call dword ptr [0040923C]
:00401301 mov eax, ebx
<- eax = offset of name
:00401303 cmp byte ptr [ebx], 00
<- cmp if byte at [ebx] is 00
:00401306 je 0040131A
<- if equal, jump, else...
* Referenced by a (U)nconditional or (C)onditional
Jump at Address:
|:00401318(C)
|
:00401308 movsx ecx, byte ptr [eax]
<- move byte from [eax] to ecx,
here, ecx=53 ('S')
:0040130B add ecx, ecx
<- ecx = ecx + ecx
ecx = 53 + 53
ecx = A6
:0040130D push eax
<- save eax
:0040130E lea edx, dword ptr [ecx+8*ecx] <-
edx = ecx * 8 + ecx
edx = A6 * 8 + A6
edx = 5D6
:00401311 add ebp, edx
<- ebp = ebp + edx
ebp = 55E + 5D6
ebp = B34
Why 55E? from the 1st
calculation remember?
:00401313 call edi
<- prepare next char
:00401315 cmp byte ptr [eax], 00
<- is byte at [eax] = 00?
:00401318 jne 00401308
<- no? then loop to next char,
with the same operations,
until eax = 00 (no more).
If done, ebp = 31F2 (12786)
Remember that.
* Referenced by a (U)nconditional or (C)onditional Jump at
Address:
|:00401306(C)
|
:0040131A lea eax, dword ptr [esp+10] <- after
this, "d eax", you'll see
1374- (remembered that?)
:0040131E push ebp
<- save ebp (12786)
* Possible StringData Ref from Data Obj ->"%d-"<- 2nd format: code1-code2
:0040131F push 00406274
:00401324 push eax
* Reference To: USER32.wsprintfA, Ord:0249h
:00401325 Call dword ptr [004092D4]
:0040132B lea eax, dword ptr [esp+1C]
:0040132F add esp, 0000000C
:00401332 push eax
:00401333 push esi
* Reference To: KERNEL32.lstrcatA, Ord:0266h <- after
this, "d eax", you
will see 1374-12786-
:00401334 Call dword ptr [0040923C]
:0040133A mov eax, ebx
<- eax = offset of name
:0040133C cmp byte ptr [ebx], 00
<- is it 00?
:0040133F je 00401359
<- yes? then jump, else...
* Referenced by a (U)nconditional or (C)onditional Jump at
Address:
|:00401357(C)
|
:00401341 movsx ecx, byte ptr [eax]
<- move byte from [eax] to ecx,
here, ecx=53 ('S')
:00401344 push eax
<- save eax
:00401345 lea ebp, dword ptr [ecx+4*ecx] <-
ebp = ecx * 4 + ecx
ebp = 53 * 4 + 53
ebp = 19F
:00401348 lea ecx, dword ptr [ecx+2*ebp]
<- ecx = ebp * 2 + ecx
ecx = 19F * 2 + 53
ecx = 391
:0040134B lea ebp, dword ptr [2*ecx+1]
<- ebp = ecx * 2 + 1
ebp = 391 * 2 + 1
ebp = 723
:00401352 call edi
<- prepare next char
:00401354 cmp byte ptr [eax], 00
<- is it 0?
:00401357 jne 00401341
<- no? then loop to next char,
with the same operations,
until eax = 00 (no more).
If done, ebp = A51 (2641)
Remember that.
* Referenced by a (U)nconditional or (C)onditional Jump at
Address:
|:0040133F(C)
|
:00401359 lea eax, dword ptr [esp+10]
<- eax = offset of the codes
:0040135D push ebp
<- save ebp
* Possible StringData Ref from Data Obj ->"%d-" <- code1-code-code3-
:0040135E push 00406274
:00401363 push eax
* Reference To: USER32.wsprintfA, Ord:0249h
:00401364 Call dword ptr [004092D4]
:0040136A lea eax, dword ptr [esp+1C]
:0040136E add esp, 0000000C
:00401371 push eax
:00401372 push esi
* Reference To: KERNEL32.lstrcatA, Ord:0266h <-
after this, "d eax", you
will see 1374-12786-2641-
:00401373 Call dword ptr [0040923C]
:00401379 mov eax, ebx
<- you remember this right?
:0040137B cmp byte ptr [ebx], 00
<- and this?
:0040137E je 00401392
<- hmmm?
* Referenced by a (U)nconditional or (C)onditional Jump at
Address:
|:00401390(C)
|
:00401380 movsx ecx, byte ptr [eax]
<- ecx = 53 ('S')
:00401383 push eax
<- save eax first for later use
:00401384 lea ebp, dword ptr [4*ecx+1D]<-
ebp = ecx * 4 + 1D
ebp = 53 * 4 + 1D
ebp = 169
:0040138B call edi
<- prepare next char
:0040138D cmp byte ptr [eax], 00
<- is it over?
:00401390 jne 00401380
<- no? then loop until eax = 00.
If done, ebp = 1FD (509 in dec)
Remember that.
Note: To put it short, the instructions above just
get the ordinal value
of the last
char of name then * 4 + 1D.
* Referenced by a (U)nconditional or (C)onditional Jump at
Address:
|:0040137E(C)
|
:00401392 lea eax, dword ptr [esp+10]
:00401396 push ebp
* Possible StringData Ref from Data Obj ->"%d" <- code1-code2-code3-code4
:00401397 push 00406270
:0040139C push eax
* Reference To: USER32.wsprintfA, Ord:0249h
:0040139D Call dword ptr [004092D4]
:004013A3 lea eax, dword ptr [esp+1C]
:004013A7 add esp, 0000000C
:004013AA push eax
:004013AB push esi
* Reference To: KERNEL32.lstrcatA, Ord:0266h <-
after this, "d eax", you
will see your real code,
mine's 1374-12786-2641-509
:004013AC Call dword ptr [0040923C]
:004013B2 pop ebp
:004013B3 pop edi
:004013B4 pop esi
:004013B5 pop ebx
:004013B6 add esp, 00000100
:004013BC ret
After taking the RET at :004013BC, you see:
:004011C7 push 00406030
<- save offset where codes are to be
:004011CC push 00406130
placed
:004011D1 call 00401280
<- calculation routine
:004011D6 lea eax, dword ptr [esp+18] <-
after this, "d eax", and you'll
see your inputed code (usercode),
here, 12345.
:004011DA add esp, 00000008
:004011DD push eax
<- save eax (usercode)
:004011DE push 00406030
<- save offset of real code.
If you noticed, 406030 is the
value of eax whenever we "d eax"
after the API lstrcatA. "d 406030"
to check :)
* Reference To: KERNEL32.lstrcmpA, Ord:0269h <- to cmp usercode, realcode
:004011E3 Call dword ptr [00409220]
:004011E9 test eax, eax
<- if ok, eax=0, if not, eax=1
:004011EB jne 00401271
<- if eax <> 0 (ie. eax=1) then jump
... if usercode=usercode, do these. I just skipped it,
simply because
... these just put your name and code to the system registry.
* Referenced by a (U)nconditional or (C)onditional Jump at
Address:
|:004011EB(C)
|
:00401271 xor eax, eax
<- eax = 0 (badboy!)
:00401273 pop edi
:00401274 pop esi
:00401275 add esp, 0000020C
:0040127B ret
<- end (hiew!)
That's it. Easy, wasn't it? Now we're ready to code. And
here's mine:
=============================================================
/*** Start Clean 1.2 Keygen by Sphinx [06/12/2000] *************************/
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
void main()
{
char Name[23];
int Count;
long int ecx, ebp, edx, Code1, Code2, Code3, Code4;
puts("\nStart Clean 1.2 Keygen by Sphinx [06/12/2000]\n");
Name[0] = 21;
printf("Enter your name: ");
cgets(Name);
if (Name[1] < 1)
{
printf("\nError: Name should be >= 1 character.\n");
exit(0);
}
ebp = 0x6A;
for (Count = 2; Count != Name[1]+2; Count++)
{
ecx = Name[Count];
Code1 = (ecx * 2) + ebp;
ebp = Code1;
}
for (Count = 2; Count != Name[1]+2; Count++)
{
ecx = Name[Count];
ecx = ecx + ecx;
edx = (ecx * 8) + ecx;
ebp = ebp + edx;
Code2 = ebp;
}
for (Count = 2; Count != Name[1]+2; Count++)
{
ecx = Name[Count];
ebp = (ecx * 4) + ecx;
ecx = Name[Count];
ecx = (ebp * 2) + ecx;
ebp = (ecx * 2) + 1;
Code3 = ebp;
}
ecx = Name[Name[1]+1];
ebp = (ecx * 4) + 0x1D;
Code4 = ebp;
printf("\nRegistration no: %lu-%lu-%lu-%lu\n", Code1, Code2,
Code3, Code4);
}
---------------------------------------------------------------[
By Sphinx ]--
|
The Keyboard Caper for his W32Dasm cracking tutorial
The +Sandman for the program
BlackBird for newbie stuff (beam.to/blackb)
|
The information in this essay is for educational purpose only!
You are only allow to crack, reverse engineer, modify code and debugg
programs that you legaly bought and then for personal use only!!
To ignore this warning is a criminell act and can result in lawful
actions!
So please note!
I take no responebility for how you use the information in this essay,
i take NO responebility for what might happen to you or your computer!
You use this information on your own risk!!
What i mean is: Please buy the software!
Essay written by Sphinx ©TRES2000. All Rights Reserved.